package com.larissa.android.quiz;

import java.util.*;

public class CompStack
{
    private final int OPSETSIZE = 13;
    private final int RIGHTOPSETSIZE = 1;       // 右单目运算符
    private final char[][] Prior =
            {
                    {'>', '>', '<', '<', '<', '<', '<', '<', '<', '<', '<', '>', '>'},
                    {'>', '>', '<', '<', '<', '<', '<', '<', '<', '<', '<', '>', '>'},
                    {'>', '>', '>', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>'},
                    {'>', '>', '>', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>'},
                    {'>', '>', '>', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>'},
                    {'>', '>', '>', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>'},
                    {'<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=', ' '},
                    {'<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=', ' '},
                    {'<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=', ' '},
                    {'<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=', ' '},
                    {'<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=', ' '},
                    {'>', '>', '>', '>', '>', '>', ' ', ' ', ' ', ' ', ' ', '>', '>'},
                    {'<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', ' ', '='}
            };
    private final char[] OPSET = {'+', '-', '×', '÷', '%', '^', 's', 'c', 't', 'r', '(', ')', '#'}; // '!'

    private final char[] RightOPSET = {'!'};

    private int ErrorFlag;
    private String CompQuestion;


    public CompStack(String text){
        this.CompQuestion = text + '#';
        ErrorFlag = 0;
    }

    public void SetCompQuestion(String text)
    {
        this.CompQuestion = text + '#';
    }

    public String GetCompQuestion()
    {
        return this.CompQuestion;
    }

    public void TestPrint()
    {
        int i, j;

        // System.out.print(Prior.length + " " + Prior[0].length);
        // System.out.println();
        // for(i=0; i<Prior.length; i++)
        // {
        //     for(j=0; j<Prior[i].length; j++)
        //     {
        //         System.out.print(Prior[i][j] + " ");
        //     }
        //     System.out.println();
        // }
        System.out.print(this.EvaluateExpression());
    }

    public double getAnswer(String text)
    {
        this.SetCompQuestion(text);
        if(ErrorFlag == 0)
        {
            return this.EvaluateExpression();
        }
        else
        {
            return -1;
        }
    }


    private double Operate(double a, char theta, double b)
    {
        if(theta == '+')
        {
            return (a+b);
        }
        else if(theta == '-')
        {
            return (b-a);
        }
        else if(theta == '×')
        {
            return (b*a);
        }
        else if(theta == '÷')
        {
            return (b/a);
        }
        else if(theta == '%')
        {
            return (b%a);
        }
        else if(theta == '^')
        {
            return Math.pow(b, a);
        }
        return -1;
    }


    private boolean InOpset(char Test)
    {
        int i;
        for (i = 0; i < OPSETSIZE; i++)
        {
            if (Test == OPSET[i])
            {
                return true;
            }
        }
        return false;
    }

    private boolean InRightSignalOpset(char Test)
    {
        int i;
        for(i=0;i<RIGHTOPSETSIZE;i++)
        {
            if(Test == RightOPSET[i])
            {
                return true;
            }
        }
        return false;
    }
    private double RightOperate(double a, char theta)
    {
        int i=1;
        int result=1;
        if(theta == '!')
        {
            for(i=1;i<a;i++)
            {
                result = result*i;
            }
            return result;
        }
        else
            return -1;
    }

    private boolean isNumber(char Test)
    {
        if((Test>='0') && (Test<='9'))
            return true;
        else
            return false;
    }

    private boolean isFirst(char Test)
    {
        if(((Test>='0') && (Test<='9')) || ((Test == 's') || (Test == 'c') || (Test == 't') || (Test == 'r')))
            return true;
        else
            return false;
    }
    private char precede(char Aop, char Bop)
    {
        int i = 0, j = 0;

        for (i = 0; i < OPSETSIZE; i++)
        {
            if (Aop == OPSET[i])
            {
                break;
            }
        }
        for (j = 0; j < OPSETSIZE; j++)
        {
            if (Bop == OPSET[j])
            {
                break;
            }
        }
        return Prior[i][j];
    }


    private double EvaluateExpression()
    {
        Stack<Character> OPTR = new Stack<Character>();
        Stack<Double> OPND = new Stack<Double>();
        String TempString;
        TempString = "";
        double TempData;
        double a, b, r;
        int len=this.CompQuestion.length();
        int i=0, j=0, k=0;
        char c=this.CompQuestion.charAt(i);
        char theta='+';
        boolean opflag = false;
        ErrorFlag = 0;

        if(!this.isFirst(c))
        {
            this.ErrorFlag = 1;
            return -1;
        }
        OPTR.push('#');
        for(i=0;i<len;i++)
        {
            opflag = false;
            c = this.CompQuestion.charAt(i);
            opflag = InOpset(c);
            if(opflag == true)
            {
                if(TempString.length() > 0)
                {
                    TempData = Double.parseDouble(TempString);
                    OPND.push(TempData);
                }
                TempString = "";

                if(InRightSignalOpset(c))
                {
                    a = OPND.peek();
                    OPND.pop();
                    r = RightOperate(a, c);
                    OPND.push(r);
                    OPTR.pop();
                }
                else
                {
                    while(this.precede(OPTR.peek(), c) == '>')
                    {
                        theta = OPTR.peek();
                        OPTR.pop();
                        a = OPND.peek();
                        OPND.pop();
                        b = OPND.peek();
                        OPND.pop();
                        r = this.Operate(a, theta, b);
                        OPND.push(r);
                    }
                    if(this.precede(OPTR.peek(), c) == '<')
                    {
                        OPTR.push(c);
                    }
                    else if(this.precede(OPTR.peek(), c) == '=')
                    {
                        if(OPTR.peek() == 's')
                        {
                            a = OPND.peek();
                            OPND.pop();
                            r = Math.sin(a);
                            OPND.push(r);
                            OPTR.pop();
                        }
                        else if(OPTR.peek() == 'c')
                        {
                            a = OPND.peek();
                            OPND.pop();
                            r = Math.cos(a);
                            OPND.push(r);
                            OPTR.pop();
                        }
                        else if(OPTR.peek() == 't')
                        {
                            a = OPND.peek();
                            OPND.pop();
                            r = Math.tan(a);
                            OPND.push(r);
                            OPTR.pop();
                        }
                        else if(OPTR.peek() == 'r')
                        {
                            a = OPND.peek();
                            OPND.pop();
                            r = Math.sqrt(a);
                            OPND.push(r);
                            OPTR.pop();
                        }
                        else if(OPTR.peek() == '(')
                        {
                            OPTR.pop();
                        }
                        else if(c == '#')
                        {
                            OPTR.pop();
                            return OPND.peek();
                        }
                    }
                    else
                    {
                        ErrorFlag = 2;
                        return -1;
                    }
                }
                // System.out.printf("%c ", c);

            }
            else
            {
                TempString = TempString + c;
            }
        }

        while(!OPND.empty())
        {
            OPND.pop();
        }
        while(!OPTR.empty())
        {
            OPTR.pop();
        }
        return -1;
    }

}
